
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include "pgmspacehlp.h"
#include<util/delay.h>
#include "RTC.h"
#include "ADC.h"
#include "LCD_driver.h"
#include "LCD_functions.h"
#include <string.h>
#include <stdlib.h>
#include "dataflash.h"
#define Log 1
#define NoLog 0
#define FALSE 0
#define TRUE (!FALSE)

//signed int increment = 0;
int buffy=0;
int pageaddress=0;
int pageintadr=0;




void * datasend (char *tem_send)
{
     /*logstart++; 
	 unsigned int i;                            
	   if(logstart == 2)
	   {
	   		for(i=0;i<=pageaddress;i++)
			{
				Page_Erase (i);
			}
	   
	   }*/
    if(buffy>=252)									        //if internaladress bigger than 252, will change the page (256 bytes per buffer)/(9bytes of string)=252 bytes per buffer as integer
     {pageaddress++; buffy=0; }							    //counter of the internaladress restart from zero

	if(pageaddress>2074)   								    //change of page
     {pageaddress=0;}
        			
	DF_SPI_init();
	DF_CS_active;						    			    //Initialization of SPI
    while(!(Read_DF_status() & 0x80)); 	                       			    //Initialization of Dataflash 
    

	Page_To_Buffer (1,pageaddress);	
	Buffer_Write_Str (1,buffy,12,tem_send);			       //Copies one or more bytes to one of the dataflash
 	Buffer_To_Page (1,pageaddress);						   //Transfers a page from dataflash SRAM buffer to flash
	buffy+=12;
															
    DF_CS_inactive;	                                   //End of Dataflash communication

   return 0;
}


char * dataretrieve (char *streingread)
{
	   
    if(pageintadr>=252)									        //if internaladress bigger than 252, will change the page (256 bytes per buffer)/(9bytes of string)=252 bytes per buffer as integer
     {pageaddress++; pageintadr=0; }							    //counter of the internaladress restart from zero

	if(pageintadr>2074)   								    //change of page
     {pageaddress=0;}
        			

	DF_SPI_init();
	DF_CS_active;										//Initialization of SPI
    while(!(Read_DF_status() & 0x80)); 									//Initialization of Dataflash 
    
	Page_To_Buffer (1,pageaddress);							//Transfers a page from flash to dataflash SRAM buffer
    Buffer_Read_Str(1,pageintadr,12,streingread);				//Reads one or more bytes from one of the dataflash
    pageintadr+=increment;
	if(pageintadr<0)
	{
		pageaddress-=pageaddress;
		pageintadr=252;
		if(pageaddress<0){pageaddress=0;}
			
	}
	else if(pageintadr>254)
	{
		pageaddress+=pageaddress;
		pageintadr=0;
		if(pageaddress>2046){pageaddress=2046;pageintadr=252;}
			
	}

	DF_CS_inactive;										//End of Dataflash communication

   return *streingread;

}



void * dataretrieve_pc (char *streingread)
{
	 int pageintadr=0;
	 int pageaddress=0;
	   
    for(pageaddress=0;pageaddress<2046;pageaddress++)
	{
		
		for(pageintadr=0; pageintadr<253;pageintadr+=12)

		
/*	if(pageintadr>=252)									        //if internaladress bigger than 252, will change the page (256 bytes per buffer)/(9bytes of string)=252 bytes per buffer as integer
     {pageaddress++; pageintadr=0; }							    //counter of the internaladress restart from zero

	if(pageintadr>2074)   								    //change of page
     {pageaddress=0;}
        			*/
	{
	DF_SPI_init();
	//DF_CS_active;										//Initialization of SPI
    while(!(Read_DF_status() & 0x80)); 									//Initialization of Dataflash 
    
	Page_To_Buffer (1,pageaddress);							//Transfers a page from flash to dataflash SRAM buffer
    Buffer_Read_Str(1,pageintadr,12,streingread);				//Reads one or more bytes from one of the dataflash
    DF_CS_inactive;
	while(!(Read_DF_status() & 0x80));
	sendString(streingread);
	_delay_ms(2000);						//End of Dataflash communication

   //return *streingread;
	}
	}
}







const int TEMP_lookup_pos[] PROGMEM =    // Positive Celsius temperatures (ADC-value)
	        {                           // from 0 to 60 degrees
	            806,796,786,775,765,754,743,732,720,709,697,685,673,661,649,
	            636,624,611,599,586,574,562,549,537,524,512,500,488,476,464,
	            452,440,429,418,406,396,385,374,364,354,344,334,324,315,306,
	            297,288,279,271,263,255,247,240,233,225,219,212,205,199,193,
	            187,
	        };

#define TEMP_lookup_pos_entries	61    // Number of entries in the posative lookup table
#define TEMP_ADC_max				923   // ADC Value at lowest temperature
#define TEMP_ADC_min				187   // ADC Value at highest temprature
#define TEMP_ADC_zero				806   // ADC Value at zero degrees C
	
	
const int TEMP_lookup_neg[] PROGMEM =    
	        {                           // from -1 to -15 degrees
	            815,825,834,843,851,860,868,876,883,891,898,904,911,917,923,
	        };
#define TEMP_lookup_neg_entries	16		

const int LIGHT_ADC[] PROGMEM = // Table used to find the Vref, when using the voltage-reading function
	        { 
	            0x35,0x60,0x80,0x0B0,0x11D,0x13D,0x15A,0x17A,0x197,0x1B9,0x1DA,
	            0x1F9,0x216,0x240,0x26D,0x282,0x2A2,0x2EF,0x332,0x3B0,0x3F2
	        };
	       
	
const float LIGHT_VOLTAGE[] PROGMEM = // Vref table correspondent to the LIGHT_ADC[] table
	        {
	            2.818,2.820,2.824,2.827,2.832,2.835,2.839,2.841,2.843,2.847,2.850,
	            2.853,2.857,2.863,2.867,2.870,2.874,2.882,2.893,2.917,2.939
	        };
	
	


/*****************************************************************************
*
*   Function name : ADC_init
*
*   Returns :       None
*
*   Parameters :    char input
*
*   Purpose :       Initialize the ADC with the selected ADC-channel
*
*****************************************************************************/
void ADC_init(void)
{
	
	ADMUX = 0x00;
//	ADMUX = ADMUX | (channel_selection);
	ADMUX = ADMUX | (1<<REFS0);
	ADCSRA = ADCSRA | (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); 
	ADCSRA = ADCSRA | (1<<ADATE);
	ADCSRB = 0x00;
}



/*****************************************************************************
*
*   Function name : ADC_read
*
*   Returns :       int ADC
*
*   Parameters :    None
*
*   Purpose :       Do a Analog to Digital Conversion
*
*****************************************************************************/
uint16_t ADC_read(int channel_selection)
{
    int i;
	    uint16_t ADC_temp;
	       
	        uint16_t ADC_total = 0;
	   
	    // To save power, the voltage over the LDR and the NTC is turned off when not used
	    // This is done by controlling the voltage from a I/O-pin (PORTF3)
	    PORTF |= (1<<PF3);  
    	DDRF |=  (1<<DDF3); 
	    ADCSRA = ADCSRA | (1<<ADEN);

		ADMUX = ADMUX | (channel_selection);		

	    for(i=0;i<5;i++)            // do the ADC conversion 10 times for better accuracy
	    {
	        ADCSRA |= (1<<ADSC);        // do single conversion
	        while(!(ADCSRA & 0x10));    // wait for conversion done, ADIF flag active
	       
	        ADC_temp = ADCW;            // read out ADCW register
	       
	        ADC_total += ADC_temp;      // accumulate result (10 samples) for averaging
	    }
	
	    ADC_total = (ADC_total/5);     // average the 10 samples
	       
	    PORTF &= ~(1<<PF3);  
    	DDRF &=  ~(1<<DDF3); 
	  
	    return ADC_total;
}

void TempCalculation(uint32_t  second)
{
	char String_to_display[6];
	char hr[3];
	char mn[3];
	char h[2] = "h";
	char m[2] = "m";
	char c[9] = "C ";
	char sign[12];					// sign character for temperature '-','+' or ' '


	uint8_t i	;			// index variable for loops
	uint8_t temperature_int;		// integer portion of the temperature
    
	uint16_t hours;
	uint16_t minutes;
				
    
    hours = second/3600;
	minutes = (second-(hours*3600))/60;

	itoa(hours, hr, 10);
	itoa(minutes, mn, 10);
	strcat(c,hr);
	strcat(c,h);
	strcat(c,mn);
	strcat(c,m);

	uint16_t ADCresult = ADC_read(TEMPERATURE_SENSOR);
	
	temperature_int = 0;

   if(ADCresult >  TEMP_ADC_zero)
   {              
   		strcpy(sign,"-");								
		
		for (i=1; i < TEMP_lookup_neg_entries; i++){  
			
				if(ADCresult == pgm_read_word(&TEMP_lookup_neg[i-1]) )
				{
				temperature_int = i;
				itoa(temperature_int, String_to_display, 10);
			
				strcat (sign, String_to_display);
				strcat (sign, c);
				//call data save
				datasend (sign);
							
				LCD_puts(sign, 1);		
				break;							
			
			} 
			else if (ADCresult < pgm_read_word(&TEMP_lookup_neg[i-1]))
			{
				if((pgm_read_word(&TEMP_lookup_neg[i-1]) - ADCresult) < (ADCresult - pgm_read_word(&TEMP_lookup_neg[i-2])))
					{
					temperature_int =  i;	
					itoa(temperature_int, String_to_display, 10);
					strcat (sign, String_to_display);
					strcat (sign, c);
					datasend (sign);
					LCD_puts(sign, 1);		
					}
					else
					{
					temperature_int =  i-1;
					itoa(temperature_int, String_to_display, 10);
					strcat (sign, String_to_display);
					strcat (sign, c);
					datasend (sign);
					LCD_puts(sign, 1);
					
					}
					break;						
			}
		}
    } else if (ADCresult < TEMP_ADC_zero )
	{	
		strcpy(sign,"+");								
        
	
        for (i=1; i < TEMP_lookup_pos_entries; i++)  {   
			
		
			if (ADCresult == pgm_read_word(&TEMP_lookup_pos[i]) )
			{ 
				temperature_int = i;
				itoa(temperature_int, String_to_display, 10);
				strcat (sign, String_to_display);
				strcat (sign, c);
				datasend (sign);
				LCD_puts(sign, 1);		
				break;						
			
			}
			else if (ADCresult > pgm_read_word(&TEMP_lookup_pos[i]))
			{ 
				if((pgm_read_word(&TEMP_lookup_neg[i-1]) - ADCresult) > (ADCresult - pgm_read_word(&TEMP_lookup_neg[i])))
					{
					temperature_int =  i;
					itoa(temperature_int, String_to_display, 10);
					strcat (sign, String_to_display);
					strcat (sign, c);
					datasend (sign);
					LCD_puts(sign, 1);			
					}
				else
					{
					temperature_int =  i-1;
					itoa(temperature_int, String_to_display, 10);
					strcat (sign, String_to_display);
					strcat (sign, c);
					datasend (sign);
					LCD_puts(sign, 1);
					}
					break;							
            }
        }        
    } else {	
										
		strcpy(sign," ");
		itoa(0, String_to_display, 10);
		strcat (sign, String_to_display);
		strcat (sign, c);
		//call data save
		datasend (sign);
		
									
    }
    
}


     
void sendChar(char data)
	{
    	int i = 0; //data inserted in USART data reg
    	UDR = data;
    	if(SREG & 0x80) 
            { 
            	while ( !(UCSRA&0x40) && (i<10000) ) // Wait until the byte is sent or we count out  
            { 
                  i++; 
            } 
  			}		
			else 
            while( !(UCSRA&0x40)); // Wait until the byte is sent          
            UCSRA=UCSRA|0x40; // Clear the TXCflag         
	}

void sendString(char s[])
	{ 
     	int i = 0; 
     	while(i < 64) // continue in case of corrupted data
    {
        if( s[i] == '\0' ) break; // quit on string terminator
        sendChar(s[i++]); 
    } 
}




void USARTinit() 
	{ 
    	 // Increase the oscillator to 2 Mhz for the 19200 baudrate: 
    	 CLKPR = (1<<CLKPCE);   // Clock Prescaler Change Enable
    	 // set prescaler = 4, Inter RC 8Mhz / 4 = 2Mhz
    	 CLKPR = (1<<CLKPS1);

    	 // Set the USART baudrate registers for 9600
     	UBRRH = 0;//(unsigned char)(baudrate>>8); 
     	UBRRL = 12;//(unsigned char)baudrate;
     
       
     	// Enable receiver and transmitter 
     	//UCSRB = (1<<RXEN)|(1<<TXEN)|(0<<RXCIE)|(0<<UDRIE);
		UCSRB=0x68;
     
     	// Set the USART to asynchronous at 8 bits no parity and 1 stop bit 
     	//UCSRC = (0<<UMSEL)|(0<<UPM0)|(0<<USBS)|(3<<UCSZ0)|(0<<UCPOL);
	UCSRC=0x06;
	    // Enable interrupts
    	sei(); 
    
   		 // Setup the interrupt mask and flags
 		PCMSK1 = (1<<PINB6) | (1<<PINB4);       // set pin-change interrupt mask
   		EIFR   = (1<<PCIF1);                    // clear external intterupt flag 1
 		EIMSK  = (1<<PCIE1);                // enable external interrupt 1   

		}





uint16_t LightIntensityCalculation()
{
	uint16_t ADCresult = ADC_read(LIGHT_SENSOR);
	return ADCresult;
}


